﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Modules.Attachment;
using Modules.Corp.Repositories;
using Modules.Project;
using Modules.System.Security;
using Modules.System.User;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Entity;
using PmSoft.Exceptions;
using PmSoft.Utilities.Pinyin;

namespace Modules.Corp
{
    /// <summary>
    /// 企业相关业务逻辑类
    /// </summary>
    [UseDI(ServiceLifetime.Scoped)]
    public class CorpService
    {
        private readonly CorpInfoRepository corpInfoRepository;
        private readonly IApplicationContext applicationContext;
        private readonly SecurityRepository securityRepository;
        private readonly CorpAttachmentService corpAttachmentService;
        private readonly CorpCodeIndexer corpCodeIndexer;
        private readonly ILogger logger;

        public CorpService(CorpInfoRepository corpInfoRepository,
            SecurityRepository securityRepository,
            IApplicationContext applicationContext,
           CorpAttachmentService corpAttachmentService,
           CorpCodeIndexer corpCodeIndexer,
            ILogger<CorpService> logger)
        {
            this.corpInfoRepository = corpInfoRepository;
            this.securityRepository = securityRepository;
            this.applicationContext = applicationContext;
            this.logger = logger;
            this.corpAttachmentService = corpAttachmentService;
            this.corpCodeIndexer = corpCodeIndexer;
        }

        /// <summary>
        /// 创建企业信息
        /// </summary>
        /// <param name="corpInfo"></param>
        /// <param name="password"></param>
        /// <param name="attachments"></param>
        /// <exception cref="BusinessException"></exception>
        public void CreateCorpInfo(CorpInfo corpInfo, string password, IEnumerable<AttachmentsForm<int>> attachments)
        {
            if (CodeExists(corpInfo.Code))
                throw new BusinessException($"企业:{corpInfo.Code}已存在");

            try
            {
                applicationContext.Transaction.Begin();//开始事务
                SysSecurity security = new();
                security.Password = SecurityPasswordHelper.EncodePassword(password, UserPasswordFormat.SM4);
                security.UserType = UserType.Corp;
                securityRepository.Insert(security);
                corpInfo.SecurityId = security.SecurityId;//将安全信息表自增主键赋值给用户表
                var old = corpInfoRepository.GetCorpInfo(corpInfo.Code);
                if (old != null)
                {
                    var olds = corpAttachmentService.GetCorpAttachmentsByObjectIdAndType(old.CorpId, 企业附件类型.营业执照, 企业附件租户.Corp);
                    corpInfoRepository.Delete(old);
                    corpAttachmentService.Deleted(olds.Select(i => i.Id));
                    corpInfo.CorpId = 0;
                    corpInfo.CheckStatus = 审核状态.待审核;
                    corpInfo.FailureReason = string.Empty;
                }
                corpInfoRepository.Insert(corpInfo);

                #region 附件

                foreach (var item in attachments)
                {
                    CorpAttachment projectAttachment = new()
                    {
                        Id = Guid.NewGuid().ToString().Replace("-", ""),
                        AttachmentId = item.AttachmentId,
                        ObjectId = corpInfo.CorpId.ToString(),
                        Tenant = 企业附件租户.Corp,
                        AttachmentType = 企业附件类型.营业执照,
                        CreateTime = DateTime.Now
                    };
                    corpAttachmentService.Create(projectAttachment);
                }

                #endregion 附件

                applicationContext.Transaction.Complete();//完成事务
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"CreateCorpInfo Exception corpCode:{corpInfo.Code}");
                throw new BusinessException("写入企业信息数据失败");
            }
        }

        /// <summary>
        /// 修改企业信息
        /// </summary>
        /// <param name="corpInfo"></param>
        /// <param name="attachments"></param>
        /// <exception cref="BusinessException"></exception>
        public void UpdateCorpInfo(CorpInfo corpInfo, IEnumerable<AttachmentsForm<int>> attachments)
        {
            try
            {
                applicationContext.Transaction.Begin();//开始事务
                if (attachments.Any())
                {
                    var olditems = corpAttachmentService.GetCorpAttachmentsByObjectIdAndType(corpInfo.CorpId, 企业附件类型.营业执照, 企业附件租户.Corp);
                    corpAttachmentService.Deleted(olditems.Select(i => i.Id));

                    #region 附件

                    foreach (var item in attachments)
                    {
                        CorpAttachment projectAttachment = new()
                        {
                            Id = Guid.NewGuid().ToString().Replace("-", ""),
                            AttachmentId = item.AttachmentId,
                            ObjectId = corpInfo.CorpId.ToString(),
                            Tenant = 企业附件租户.Corp,
                            AttachmentType = 企业附件类型.营业执照,
                            CreateTime = DateTime.Now
                        };
                        corpAttachmentService.Create(projectAttachment);
                    }

                    #endregion 附件
                }
                corpInfoRepository.Update(corpInfo);

                applicationContext.Transaction.Complete();//完成事务
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"UpdateCorpInfo Exception corpCode:{corpInfo.Code}");
                throw new BusinessException("编辑企业信息数据失败");
            }
        }

        /// <summary>
        /// 无事务创建企业
        /// </summary>
        /// <param name="corpInfo"></param>
        /// <param name="password"></param>
        public CorpInfo CreateCorpInfoNoTransaction(CorpInfo corpInfo)
        {
            if (CodeExists(corpInfo.Code))
                throw new BusinessException($"企业:{corpInfo.Code}已存在");
            SysSecurity security = new();
            security.Password = SecurityPasswordHelper.EncodePassword(SecurityPasswordHelper.EncodePassword("Xzhr.123456", UserPasswordFormat.SM3), UserPasswordFormat.SM4);
            security.UserType = UserType.Corp;
            securityRepository.Insert(security);
            corpInfo.SecurityId = security.SecurityId;//将安全信息表自增主键赋值给用户表
            corpInfo.CheckStatus = 审核状态.审核通过;
            corpInfoRepository.Insert(corpInfo);
            return corpInfo;
        }

        /// <summary>
        /// 用户密码认证登录
        /// </summary>
        /// <param name="corpCode"></param>
        /// <param name="password"></param>
        public CorpInfo? PasswordSignIn(string corpCode, string password)
        {
            var security = GetSecurity(corpCode);
            if (security == null)
                throw new BusinessException("企业信用代码或密码错误");

            if (!SecurityPasswordHelper.CheckPassword(password, security.Password, UserPasswordFormat.SM4))
                throw new BusinessException("企业信用代码或密码错误");

            HandleLogin(security);

            return GetCorpInfo(corpCode);
        }

        /// <summary>
        /// 登陆处理
        /// </summary>
        /// <param name="security"></param>
        private void HandleLogin(SysSecurity security)
        {
            securityRepository.UpdateLoginInfoStatus(security, applicationContext.ClientIp, DateTime.Now);
        }

        public bool CodeExists(string code)
        {
            return corpInfoRepository.CodeExists(code);
        }

        public void Delete(int id)
        {
            corpCodeIndexer.Remove(id);//删除索引
            corpInfoRepository.DeleteByEntityId(id);
        }

        public void Deletes(IEnumerable<int> ids)
        {
            foreach (var id in ids)
            {
                Delete(id);
            }
        }

        public CorpInfo? GetCorpInfo(int corpId)
        {
            return corpInfoRepository.Get(corpId);
        }

        public CorpInfo? GetCorpInfo(string corpCode)
        {
            int? id = corpCodeIndexer.GetId(corpCode);
            if (id.HasValue && id > 0)
                return GetCorpInfo(id.Value);
            else
                return null;
        }

        public IEnumerable<CorpInfo> GetCorpInfos(IEnumerable<string> corpCode)
        {
            return corpInfoRepository.GetCorpInfos(corpCode);
        }

        public SysSecurity? GetSecurity(string corpCode)
        {
            var corpInfo = GetCorpInfo(corpCode);
            if (corpInfo == null)
                return null;
            return securityRepository.Get(corpInfo.SecurityId);
        }

        /// <summary>
        /// 企业信息分页-适用于全局企业查询
        /// </summary>
        /// <param name="query"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public IPagedList<CorpInfo> GetCorpInfos(CorpInfoQuery query, int pageIndex, int pageSize, IEnumerable<int?> corpIds = null)
        {
            return corpInfoRepository.GetCorpInfos(query, pageIndex, pageSize, corpIds);
        }

        /// <summary>
        /// 按企业名称搜索企业
        /// </summary>
        /// <param name="keywords"></param>
        /// <returns></returns>
        public IEnumerable<CorpInfo> SearchCorps(string keywords, int limit = 10)
        {
            return corpInfoRepository.SearchCorps(keywords, limit);
        }

        public IEnumerable<CorpInfo> GetCorpInfos(IEnumerable<int> ids)
        {
            return corpInfoRepository.PopulateEntitiesByEntityIds(ids);
        }

        public IEnumerable<CorpInfo> GetCorpsByProjectId(int? projectId)
        {
            return corpInfoRepository.GetCorpsByProjectId(projectId);
        }

        public void UpdateDefaultProjectId(CorpInfo corpInfo, int projectId)
        {
            corpInfoRepository.UpdateDefaultProjectId(corpInfo, projectId);
        }

        public IPagedList<CorpInfo> GetCorpInfosByProjectId(CorpInfoQuery query, int pageIndex, int pageSize)
        {
            return corpInfoRepository.GetCorpInfosByProjectId(query, pageIndex, pageSize);
        }

        public IEnumerable<CorpInfo> GetCorpsByCorpIds(IEnumerable<int> corpIds)
        {
            return corpInfoRepository.PopulateEntitiesByEntityIds(corpIds);
        }

        /// <summary>
        /// 获取项目下所有参加企业,包括总包
        /// </summary>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public IEnumerable<CorpInfo> GetCorpsByProjectId(int projectId)
        {
            var projectInfo = applicationContext.GetService<ProjectService>().GetProjectInfo(projectId);
            if (projectInfo == null)
                throw new ArgumentNullException(nameof(projectInfo));
            var projectCorps = applicationContext.GetService<ProjectCorpService>().GetProjectCorpsByProjectId(projectId);
            var corpIds = projectCorps.Select(a => a.CorpId).ToList();
            corpIds.Add(projectInfo.LumpContractorCorpId);
            return GetCorpsByCorpIds(corpIds);
        }

        /// <summary>
        /// 获取除监理以外的总包分包
        /// </summary>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public IEnumerable<CorpInfo> GetCorpsNoJLByPrjectId(int projectId)
        {
            var projectInfo = applicationContext.GetService<ProjectService>().GetProjectInfo(projectId);
            if (projectInfo == null)
                throw new ArgumentNullException(nameof(projectInfo));
            var projectCorps = applicationContext.GetService<ProjectCorpService>().GetProjectCorpsByProjectId(projectId);
            var corpIds = projectCorps.Where(i => i.Role != 项目参建单位类型.监理).Select(a => a.CorpId).ToList();
            corpIds.Add(projectInfo.LumpContractorCorpId);
            return GetCorpsByCorpIds(corpIds);
        }

        public void Update(CorpInfo corpInfo)
        {
            corpInfoRepository.Update(corpInfo);
        }

        /// <summary>
        /// 审核企业(通过)
        /// </summary>
        /// <param name="corpId">企业Id</param>
        public void AuditCorpSuccess(int corpId)
        {
            var corp = GetCorpInfo(corpId) ?? throw new BusinessException("企业信息不存在");
            if (corp.CheckStatus != 审核状态.待审核) throw new BusinessException("该企业不需要审核");
            corp.CheckStatus = 审核状态.审核通过;
            Update(corp);
        }

        /// <summary>
        /// 审核企业(失败)
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="reasons"></param>
        public void AuditCorpFail(int corpId, string reasons)
        {
            var corp = GetCorpInfo(corpId) ?? throw new BusinessException("企业信息不存在");
            if (corp.CheckStatus != 审核状态.待审核) throw new BusinessException("该企业不需要审核");
            corp.CheckStatus = 审核状态.审核失败;
            corp.FailureReason = reasons;
            Update(corp);
        }
    }
}